#include"Logger.h"
#include"Utils.h"
#include"LogStream.h"
#include"AsyncLogging.h"
using namespace std;
using namespace Log;

const char* Logger::LogLevelName[Logger::NUM_LOG_LEVELS] =
{
  "TRACE ",
  "DEBUG ",
  "INFO  ",
  "WARN  ",
  "ERROR ",
  "FATAL ",
};

Logger::Impl::Impl(LogLevel level, const SourceFile& file, int line): 
    stream_(),
    level_(level),
    line_(line),
    basename_(file)
{
    stream_ << Utils::getTime()<<"-";
    stream_ << Utils::getTid() << "-";
    stream_ << LogLevelName[level] <<"-";
}


void Logger::Impl::finish()
{
    stream_ << " - " << basename_ << '\n';//???
}

Logger::Logger(SourceFile file, int line)
    : impl_(INFO, file, line)
{
}

Logger::Logger(SourceFile file, int line, LogLevel level, const char* func)
    : impl_(level, file, line)
{
    impl_.stream_ << func << ' ';
}

Logger::Logger(SourceFile file, int line, LogLevel level)
    : impl_(level, file, line)
{
}

Logger::Logger(SourceFile file, int line, bool toAbort)
    : impl_(toAbort ? FATAL : ERROR, file, line)
{
}

Logger::~Logger()
{
    impl_.finish();
    const auto& buf = stream().buffers();
    for(auto it= buf.cbegin();it!= buf.cend();++it)
        g_output((*it)->data(), (*it)->size());
    if (impl_.level_ == FATAL)
    {
        g_flush();
        abort();
    }
}

void Logger::setLogLevel(Logger::LogLevel level)
{
    g_logLevel = level;
}

void Logger::setOutput(OutputFunc out)
{
    g_output = out;
}

void Logger::setFlush(FlushFunc flush)
{
    g_flush = flush;
}


void defaultOutput(const char* msg, int len)
{
    size_t n = fwrite(msg, 1, len, stdout);
    //FIXME check n
    (void)n;
}

void defaultFlush()
{
    fflush(stdout);
}

Logger::LogLevel initLogLevel()
{
    if (::getenv("LOG_TRACE"))
        return Logger::TRACE;
    else if (::getenv("LOG_DEBUG"))
        return Logger::DEBUG;
    else
        return Logger::INFO;
}

static const string basename = "Log//";
static int rollsize = 16 * 1024 * 1024;  //16M
static AsyncLogging asyncLogging(basename, rollsize);

void asyncOutput(const char* msg, int len)
{
    asyncLogging.append(msg, len);
}

void asyncFlush()
{

}

//Logger::FlushFunc setAsyncLoggingFlushFunc() {
//    return &asyncLogging.append;
//}

Logger::LogLevel Logger::g_logLevel = initLogLevel();
//Logger::OutputFunc Logger::g_output = defaultOutput;
//Logger::FlushFunc Logger::g_flush = defaultFlush;
Logger::OutputFunc Logger::g_output = asyncOutput;
Logger::FlushFunc Logger::g_flush = asyncFlush;
